package apiserver

import (
	"crypto/md5"
	"encoding/hex"
	"fmt"
	"git.hortorgames.com/orange/tang/http"
	"git.hortorgames.com/orange/tang/mongo"
	"git.hortorgames.com/orange/tang/redis"
	"git.hortorgames.com/orange/tang/storage"
	"git.hortorgames.com/serverless/htgserver/apiserver/data"
	"time"
)

type Context struct {
	*http.Context
	RequestTime time.Time
	RequestData *Request
	rawData     []byte
	Secret      string
	Game        *data.TDGame
	AntiResend  bool
	UseXor      bool
}

type ContextMongoSession struct {
	*mongo.Session
}

func (ctx *Context) GetRawData() (data []byte, err error) {
	if len(ctx.rawData) > 0 {
		return ctx.rawData, nil
	}
	ctx.rawData, err = ctx.Context.Context.GetRawData()
	return ctx.rawData, err
}

func (ctx *Context) StartMongoSession() (*mongo.Session, error) {
	mongo := storage.GetMongoClient("default")
	if mongo == nil {
		return nil, fmt.Errorf("mongo is nil")
	}
	sess, err := mongo.StartSession()
	if err != nil {
		return nil, err
	}
	sess.SetLogger(ctx.Logger()).DBImmutable("game_" + ctx.Game.Id)
	return sess, nil
}

func (ctx *Context) UsingMongoSession(action func(sess *mongo.Session) error) error {
	sess, err := ctx.StartMongoSession()
	if err != nil {
		return err
	}
	defer sess.End()
	return action(sess)
}

func (ctx *Context) StartRedisSession() *redis.Session {
	redis := storage.GetRedisClient("default")
	sess := redis.StartSession()
	sess.SetLogger(ctx.Logger()).SetNamespaceImmutable("game_" + ctx.Game.Id)
	return sess
}

func (ctx *Context) UsingRedisSession(action func(sess *redis.Session) error) error {
	sess := ctx.StartRedisSession()
	defer sess.End()
	return action(sess)
}

func (ctx *Context) VerifySign(secret string) bool {
	ctx.Secret = secret
	bytes, err := ctx.GetRawData()
	if err != nil {
		ctx.Logger().Error("GetRawData error", "err", err.Error())
		return false
	}
	hash := md5.New()
	hash.Reset()
	hash.Write(bytes)
	hash.Write([]byte(secret))
	sign := hex.EncodeToString(hash.Sum(nil))
	got := ctx.GetHeader("Sign")
	if sign != got {
		ctx.Logger().Error("Sign error", "calc", sign, "got", got)
		return false
	}
	return true
}

type Response struct {
	Seq   int32       `json:"seq,omitempty" msgpack:"seq,omitempty"`
	RSeq  int32       `json:"rSeq,omitempty" msgpack:"rSeq,omitempty"`
	Code  int32       `json:"code,omitempty" msgpack:"code,omitempty"`
	Error string      `json:"error,omitempty" msgpack:"error,omitempty"`
	Time  int64       `json:"time,omitempty" msgpack:"time,omitempty"` // 服务器时间，毫秒数
	Body  interface{} `json:"body,omitempty" msgpack:"body,omitempty"`
}

//type contextDecoder struct {
//	contextWrapper http.ContextWrapper
//}
//
//func (d *contextDecoder) Decode(ctx http.IContext, params interface{}) {
//	var err error
//	defer func() {
//		if err != nil {
//			log.Error("decode params error", "err", err.Error())
//		}
//	}()
//
//	if ctx.Request().Method == "GET" || ctx.ContentType() == "application/x-www-form-urlencoded" {
//		err = ctx.Request().ParseForm()
//		if err != nil {
//			return
//		}
//		tmp := map[string]interface{}{}
//		for k, v := range ctx.Request().Form {
//			if len(v) > 0 {
//				vv := v[0]
//				if strings.HasPrefix(vv, "{") || strings.HasPrefix(vv, "[") {
//					var obj interface{}
//					err := utils.JsonDecodeString(vv, &obj)
//					if err == nil {
//						tmp[k] = obj
//						continue
//					}
//				}
//				if strings.HasPrefix(vv, "~") {
//					vv = vv[1:]
//				}
//				tmp[k] = vv
//			}
//		}
//		json := utils.JsonEncodeToStringMust(tmp)
//		err = utils.JsonDecodeString(json, params)
//	} else if ctx.ContentType() == "application/json" {
//		bytes, err := ctx.GetRawData()
//		if err != nil {
//			return
//		}
//		err = utils.JsonDecode(bytes, params)
//	} else if ctx.ContentType() == "application/octet-stream" {
//		//req, ok := ctx.Get("_req")
//		//if !ok {
//		//	bytes, err := ctx.GetRawData()
//		//	if err != nil {
//		//		return
//		//	}
//		//	bytes, err = utils.GzipDecode(bytes)
//		//	if err != nil {
//		//		return
//		//	}
//		//	var req2 Request
//		//	err = utils.BonDecode(bytes, &req2)
//		//	if err != nil {
//		//		return
//		//	}
//		//	ctx.Set("_req", req2)
//		//	req = req2
//		//	ctx.(*Context).ReqSeq = req2.Seq
//		//}
//		//var obj interface{}
//		//utils.BonDecode(unzipped.([]byte), &obj)
//		//println(utils.JsonEncodeToStringMust(obj))
//
//		//println(base64.StdEncoding.EncodeToString(unzipped.([]byte)))
//		//err = utils.BonDecode(unzipped.([]byte), req)
//		//if err != nil {
//		//	return
//		//}
//		//ctx.(*Context).ReqSeq = req.Seq
//	}
//}
//
//func (d *contextDecoder) ContextWrapper() http.ContextWrapper {
//	return d.contextWrapper
//}
